#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
AI营销方案生成系统 - Flask应用主入口
配置Flask应用、数据库连接、中间件和路由注册

主要功能：
- Flask应用初始化和配置
- 数据库连接管理
- 中间件配置（CORS、日志、错误处理）
- API路由注册
- WebSocket支持
- 环境配置管理
- 应用生命周期管理

环境变量：
- FLASK_ENV: 运行环境 (development/production)
- MONGODB_URI: MongoDB连接字符串
- REDIS_URL: Redis连接字符串
- SECRET_KEY: Flask密钥
- CORS_ORIGINS: 允许的跨域源
- LOG_LEVEL: 日志级别

Author: AI Marketing System
Date: 2024
"""

import os
import sys
from datetime import datetime, timezone
from typing import Dict, Any, Optional

from flask import Flask, request, jsonify, g
from flask_cors import CORS
from flask_socketio import SocketIO
from werkzeug.middleware.proxy_fix import ProxyFix
import logging
from logging.handlers import RotatingFileHandler
import uuid
import traceback

# 添加项目根目录到Python路径
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))

from config.settings import Config, get_config_by_name
from config.database import init_database, get_database, close_database
# from utils.logger import setup_logging  # 暂时注释，使用Flask默认日志
# from utils.client_info import get_client_info  # 暂时注释，不存在该模块
# 导入路由蓝图
from routes.template_routes import template_bp
from routes.requirement_routes import requirement_bp
from routes.chat_routes import chat_bp
# from routes.websocket_handlers import socketio as chat_socketio  # 不再需要直接导入


def create_app(config_name: str = None):
    """
    应用工厂函数
    创建并配置Flask应用实例
    
    Args:
        config_name (str): 配置名称 ('development', 'testing', 'production')
        
    Returns:
        tuple: (Flask应用实例, SocketIO实例)
    """
    # 创建Flask应用
    app = Flask(__name__)
    
    # 加载配置
    config_obj = get_config_by_name(config_name)
    app.config.from_object(config_obj)
    
    # 初始化配置
    config_obj.init_app(app)
    
    # 配置代理支持（用于生产环境）
    if app.config.get('PROXY_FIX_ENABLED', False):
        app.wsgi_app = ProxyFix(
            app.wsgi_app,
            x_for=1,
            x_proto=1,
            x_host=1,
            x_prefix=1
        )
    
    # 初始化数据库
    # 注意：init_database是异步函数，需要在应用启动时调用
    # init_database()  # 暂时注释，稍后处理异步初始化
    
    # 配置日志
    setup_app_logging(app)
    
    # 配置CORS
    setup_cors(app)
    
    # 注册中间件
    register_middleware(app)
    
    # 注册错误处理器
    register_error_handlers(app)
    
    # 注册应用生命周期钩子
    register_lifecycle_hooks(app)
    
    # 初始化SocketIO
    socketio = SocketIO(
        app,
        cors_allowed_origins=app.config.get('CORS_ORIGINS', '*'),
        async_mode='threading',
        logger=app.config.get('SOCKETIO_LOGGER', False),
        engineio_logger=app.config.get('SOCKETIO_ENGINEIO_LOGGER', False)
    )
    
    # 将SocketIO实例绑定到应用
    app.socketio = socketio
    
    # 注册SocketIO事件处理器
    from routes import register_routes
    register_routes(app, socketio)
    
    app.logger.info(f"Flask应用创建成功 - 环境: {app.config.get('ENV', 'unknown')}")
    
    # 返回应用实例和socketio实例
    return app, socketio


def setup_app_logging(app: Flask) -> None:
    """
    配置应用日志
    
    Args:
        app: Flask应用实例
    """
    # 设置日志级别
    log_level = getattr(logging, app.config.get('LOG_LEVEL', 'INFO').upper())
    app.logger.setLevel(log_level)
    
    # 如果不是调试模式，配置文件日志
    if not app.debug and not app.testing:
        # 确保日志目录存在
        log_dir = app.config.get('LOG_DIR', 'logs')
        if not os.path.exists(log_dir):
            os.makedirs(log_dir)
        
        # 配置文件处理器
        file_handler = RotatingFileHandler(
            os.path.join(log_dir, 'app.log'),
            maxBytes=10240000,  # 10MB
            backupCount=10
        )
        
        file_handler.setFormatter(logging.Formatter(
            '%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
        ))
        
        file_handler.setLevel(log_level)
        app.logger.addHandler(file_handler)
        
        app.logger.info('应用日志配置完成')


def setup_cors(app: Flask) -> None:
    """
    配置跨域资源共享
    
    Args:
        app: Flask应用实例
    """
    cors_origins = app.config.get('CORS_ORIGINS', '*')
    
    # 如果是字符串，转换为列表
    if isinstance(cors_origins, str):
        if cors_origins == '*':
            origins = '*'
        else:
            origins = [origin.strip() for origin in cors_origins.split(',')]
    else:
        origins = cors_origins
    
    # 确保包含3002端口
    if isinstance(origins, list):
        additional_origins = ['http://localhost:3002', 'http://127.0.0.1:3002']
        for origin in additional_origins:
            if origin not in origins:
                origins.append(origin)
    
    CORS(
        app,
        origins=origins,
        methods=['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
        allow_headers=[
            'Content-Type',
            'Authorization',
            'X-Requested-With',
            'X-Request-ID',
            'X-Client-Info'
        ],
        expose_headers=['X-Request-ID', 'X-Total-Count'],
        supports_credentials=True,
        max_age=3600
    )
    
    app.logger.info(f"CORS配置完成 - 允许源: {origins}")


def register_middleware(app: Flask) -> None:
    """
    注册中间件
    
    Args:
        app: Flask应用实例
    """
    
    @app.before_request
    def before_request():
        """
        请求前处理
        """
        # 生成请求ID
        g.request_id = str(uuid.uuid4())
        g.start_time = datetime.now(timezone.utc)
        
        # 获取客户端信息
        g.client_info = {
            'ip': request.environ.get('HTTP_X_FORWARDED_FOR', request.remote_addr),
            'user_agent': request.headers.get('User-Agent', '')
        }
        
        # 记录请求开始
        if app.config.get('LOG_REQUESTS', True):
            app.logger.info(
                f"请求开始 - ID: {g.request_id} - 方法: {request.method} - "
                f"路径: {request.path} - IP: {g.client_info['ip']} - "
                f"User-Agent: {g.client_info['user_agent'][:100]}"
            )
    
    @app.after_request
    def after_request(response):
        """
        请求后处理
        
        Args:
            response: Flask响应对象
        
        Returns:
            Flask响应对象
        """
        # 添加请求ID到响应头
        if hasattr(g, 'request_id'):
            response.headers['X-Request-ID'] = g.request_id
        
        # 添加安全头
        response.headers['X-Content-Type-Options'] = 'nosniff'
        response.headers['X-Frame-Options'] = 'DENY'
        response.headers['X-XSS-Protection'] = '1; mode=block'
        
        # 计算响应时间
        if hasattr(g, 'start_time'):
            response_time = (datetime.now(timezone.utc) - g.start_time).total_seconds() * 1000
            response.headers['X-Response-Time'] = f"{response_time:.2f}ms"
            
            # 记录请求完成
            if app.config.get('LOG_REQUESTS', True):
                app.logger.info(
                    f"请求完成 - ID: {g.request_id} - 状态: {response.status_code} - "
                    f"响应时间: {response_time:.2f}ms"
                )
            
            # 记录慢请求
            slow_request_threshold = app.config.get('SLOW_REQUEST_THRESHOLD', 1000)  # 1秒
            if response_time > slow_request_threshold:
                app.logger.warning(
                    f"慢请求检测 - ID: {g.request_id} - 方法: {request.method} - "
                    f"路径: {request.path} - 响应时间: {response_time:.2f}ms"
                )
                
                # 慢请求已记录到应用日志中
        
        return response
    
    app.logger.info("中间件注册完成")


def register_blueprints(app: Flask) -> None:
    """
    注册蓝图
    
    Args:
        app: Flask应用实例
    """
    # 注册核心功能蓝图
    app.register_blueprint(template_bp, url_prefix='/api')
    app.register_blueprint(requirement_bp, url_prefix='/api')
    app.register_blueprint(chat_bp, url_prefix='/api')
    
    app.logger.info("API蓝图注册完成")


def register_error_handlers(app: Flask) -> None:
    """
    注册错误处理器
    
    Args:
        app: Flask应用实例
    """
    
    @app.errorhandler(400)
    def bad_request(error):
        """处理400错误"""
        return jsonify({
            'success': False,
            'message': '请求参数错误',
            'code': 400,
            'error_code': 'BAD_REQUEST',
            'request_id': getattr(g, 'request_id', None)
        }), 400
    
    @app.errorhandler(401)
    def unauthorized(error):
        """处理401错误"""
        return jsonify({
            'success': False,
            'message': '未授权访问',
            'code': 401,
            'error_code': 'UNAUTHORIZED',
            'request_id': getattr(g, 'request_id', None)
        }), 401
    
    @app.errorhandler(403)
    def forbidden(error):
        """处理403错误"""
        return jsonify({
            'success': False,
            'message': '禁止访问',
            'code': 403,
            'error_code': 'FORBIDDEN',
            'request_id': getattr(g, 'request_id', None)
        }), 403
    
    @app.errorhandler(404)
    def not_found(error):
        """处理404错误"""
        return jsonify({
            'success': False,
            'message': '资源不存在',
            'code': 404,
            'error_code': 'NOT_FOUND',
            'request_id': getattr(g, 'request_id', None)
        }), 404
    
    @app.errorhandler(405)
    def method_not_allowed(error):
        """处理405错误"""
        return jsonify({
            'success': False,
            'message': '请求方法不允许',
            'code': 405,
            'error_code': 'METHOD_NOT_ALLOWED',
            'request_id': getattr(g, 'request_id', None)
        }), 405
    
    @app.errorhandler(413)
    def request_entity_too_large(error):
        """处理413错误"""
        return jsonify({
            'success': False,
            'message': '请求实体过大',
            'code': 413,
            'error_code': 'REQUEST_TOO_LARGE',
            'request_id': getattr(g, 'request_id', None)
        }), 413
    
    @app.errorhandler(429)
    def rate_limit_exceeded(error):
        """处理429错误"""
        return jsonify({
            'success': False,
            'message': '请求频率超限',
            'code': 429,
            'error_code': 'RATE_LIMIT_EXCEEDED',
            'request_id': getattr(g, 'request_id', None)
        }), 429
    
    @app.errorhandler(500)
    def internal_server_error(error):
        """处理500错误"""
        error_id = str(uuid.uuid4())
        
        # 记录详细错误信息
        app.logger.error(
            f"内部服务器错误 - 错误ID: {error_id} - 请求ID: {getattr(g, 'request_id', 'unknown')} - "
            f"错误: {str(error)} - 堆栈: {traceback.format_exc()}"
        )
        

        
        return jsonify({
            'success': False,
            'message': '内部服务器错误',
            'code': 500,
            'error_code': 'INTERNAL_SERVER_ERROR',
            'error_id': error_id,
            'request_id': getattr(g, 'request_id', None)
        }), 500
    
    @app.errorhandler(Exception)
    def handle_exception(error):
        """处理未捕获的异常"""
        error_id = str(uuid.uuid4())
        
        # 记录详细错误信息
        app.logger.error(
            f"未捕获异常 - 错误ID: {error_id} - 请求ID: {getattr(g, 'request_id', 'unknown')} - "
            f"异常类型: {type(error).__name__} - 错误: {str(error)} - 堆栈: {traceback.format_exc()}"
        )
        

        
        return jsonify({
            'success': False,
            'message': '系统异常',
            'code': 500,
            'error_code': 'UNHANDLED_EXCEPTION',
            'error_id': error_id,
            'request_id': getattr(g, 'request_id', None)
        }), 500
    
    app.logger.info("错误处理器注册完成")


def register_lifecycle_hooks(app: Flask) -> None:
    """
    注册应用生命周期钩子
    
    Args:
        app: Flask应用实例
    """
    
    @app.teardown_appcontext
    def close_db_connection(error):
        """
        应用上下文销毁时关闭数据库连接
        
        Args:
            error: 错误信息
        """
        # 注意：close_database是异步函数，需要特殊处理
        # 暂时注释，稍后处理异步关闭
        # close_database()
    
    app.logger.info("生命周期钩子注册完成")


# 创建应用实例
app, socketio = create_app()


if __name__ == '__main__':
    """
    应用入口点
    """
    # 获取配置
    host = os.environ.get('FLASK_HOST', '127.0.0.1')
    port = int(os.environ.get('FLASK_PORT', 5001))
    debug = os.environ.get('FLASK_ENV') == 'development'
    
    app.logger.info(
        f"启动Flask应用 - 主机: {host} - 端口: {port} - 调试模式: {debug}"
    )
    
    # 使用SocketIO运行应用
    socketio.run(
        app,
        host=host,
        port=port,
        debug=debug,
        use_reloader=debug,
        log_output=debug
    )